import Vue from 'vue';
import { GetterTree, ActionTree, MutationTree } from 'vuex';
import { RootState } from '~/store';
import { ICommentModel } from '~/models/comment.model';
import { IListPagination } from '~/models/list-pagination.model';

interface ICommentState {
  list: ICommentModel[];
  hasMore: boolean;
  searchCriteria: {
    pageIndex: number;
    pageSize: number;
    articleId?: string;
  };
  [key: string]: any;
}

export const state: () => ICommentState = () => ({
  list: [],
  hasMore: true,
  searchCriteria: {
    pageIndex: 1,
    pageSize: 10,
  },
});

export type UserModuleState = ReturnType<typeof state>;

export const getters: GetterTree<UserModuleState, RootState> = {
  list: state => state.list || [],
};

export const mutations: MutationTree<UserModuleState> = {
  SET_CRITERIA: (state, payload: any) => state.searchCriteria = payload,
  SET_HAS_MORE: (state, payload: boolean) => state.hasMore = payload,
  
  GET_LIST: (state, payload: IListPagination<ICommentModel>) => {
    if (payload.pageIndex === 1) {
      state.list = payload.items;
    } else {
      const list: ICommentModel[] = [];
      payload.items.forEach(item => {
        if (state.list.every(d => d._id !== item._id)) {
          list.push(item);
        }
      });
      state.list = [...state.list, ...list];
    }
  },
  
  UPDATE_COMMENT: (state, payload: ICommentModel) => {
    if (payload.replyCommentId) {
      const obj = getCurrentItemAndIndex(state.list, payload.replyCommentId);
      if (obj.currentItem && obj.currentItem.replyComments) {
        obj.currentItem.replyComments.forEach((item, index) => {
          if (item._id === payload._id) {
            Vue.set((state.list[obj.currentItemIdx] as any).replyComments, index, { ...item, ...payload });
          }
        });
      }
    } else {
      const findItemIndex = state.list.findIndex(d => d._id === payload._id);
      state.list.splice(findItemIndex, 1, payload);
    }
  },
  
  ADD_COMMENT: (state, payload: any) => {
    if (!payload._id) return;
    if (payload.replyCommentId) {
      const obj = getCurrentItemAndIndex<ICommentModel>(state.list, payload.replyCommentId);
      
      if (obj.currentItem) {
        obj.currentItem.replyComments ? obj.currentItem.replyComments.push(payload) : (obj.currentItem.replyComments = [payload]);
        state.list.splice(obj.currentItemIdx, 1, obj.currentItem);
      }
    } else {
      state.list.unshift(payload);
    }
  },
};

export const actions: ActionTree<UserModuleState, RootState> = {
  /**
   * 获取评论列表
   * @param commit
   * @param payload 查询条件
   */
  getList({ commit, rootGetters }, payload: any): Promise<void> {
    const params = {
      articleId: payload.articleId,
      userId: rootGetters['user/userInfo']._id,
      pageIndex: payload.pageIndex,
      pageSize: payload.pageSize,
    };
    commit('SET_CRITERIA', params);
    return this.$axios.get<IListPagination<ICommentModel>>('/blog/comment/list', { params }).then((res: any) => {
      if (res) {
        commit('GET_LIST', res);
        commit('SET_HAS_MORE', res.pageIndex < res.pageCount);
      }
    });
  },
  
  /**
   * 创建评论/回复
   * @param commit
   * @param payload
   */
  addComment({ commit }, payload: any): Promise<void> {
    const savedData = {
      articleId: payload.articleId,
      content: payload.content,
      to: payload.to,
      replyCommentId: payload.replyCommentId,
    };
    return this.$axios.post<ICommentModel>('/blog/comment/add', savedData).then((res: any) => {
      if (res) {
        commit('ADD_COMMENT', res);
      }
    });
  },
  
  /**
   * 更新评论/回复
   * @param commit
   * @param payload
   */
  updateComment({ commit }, payload: ICommentModel): Promise<void> {
    return new Promise(resolve => {
      commit('UPDATE_COMMENT', payload);
      resolve();
    });
  }
};

/**
 * 查找当前列表中与传入回复id匹配的 item 和 index
 * @param list
 * @param replyCommentId
 */
function getCurrentItemAndIndex<T>(list: T[] = [], replyCommentId: string | undefined): { currentItem: T | undefined; currentItemIdx: number } {
  let currentItem: T | undefined;
  let currentItemIdx!: number;
  for (let i = 0; i < list.length; i += 1) {
    const item = list[i] as any;
    if (item._id === replyCommentId) {
      currentItem = item;
      currentItemIdx = i;
      continue;
    }
  }
  return { currentItem, currentItemIdx };
}
